﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Kinect;
using Kinect.Toolbox;
using System.IO;
using Kinect.Toolbox.Record;
using Microsoft.Win32;
using System.Threading;
using DetectingKinectSencor.RecordStream;
using System.Collections;
using DetectingKinectSencor.BodyLanguage;
using System.ComponentModel;
using DetectingKinectSencor._02_Oral_Communication;
using System.Diagnostics;
using DetectingKinectSencor.Tools;
using System.Data.SQLite;
using DetectingKinectSencor._03_Slides;
using DetectingKinectSencor._40_Tools;

namespace DetectingKinectSencor
{

    /// <summary>
    /// Interaktionslogik für MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

        #region Member Variables

        //********************************************//
        //************ Debug Variable ****************//
        //********************************************//
        public static bool DEBUGon = false;

        public static bool DEBUGrecordColorStream = false;
        public static bool DEBUGrecordDepthStream = false;
        public static bool DEBUGrecordSkeltonStream = false;
        public static bool DEBUGrecordAudioStream = true;


        public static bool DEBUGplayColorStream = false;
        public static bool DEBUGplayDepthStream = false;
        public static bool DEBUGplaySkeltonStream = false;

        public static bool DEBUGdepthStreamManager = false;
        public static bool DEBUGcolorStreamManager = false;


        public static bool DEBUGplayStream = false;

        public static bool DEBUGstreamWriterRecord = false;
        public static bool DEBUGstreamWriterReplay = false;

        //Kinect sensor variable
        private KinectSensor _kinectSensor;

        //Color variables
        private ColorStreamManager colorStreamManager;
        private RecordStreams recordColorStreams;

        //Depth variables
        private DepthStreamManager depthStreamManager;
        private RecordStreams recordDepthStreams;

        //Skeleton variables
        private Skeleton[] skeletonsPreview;
        private SkeletonDisplayManager skeletonManager;
        private RecordStreams recordSkeletonStreams;

        // Audio variables
        private KinectAudioSource audioSource;
        private RecordAudioStream recordAudioStream;
        private FileStream fsAudio;
        private BufferedStream bsAudio;

        // Object which controls the stream replay
        private PlayStreams replay;

        // Bolean variable which turns to true if the checkbox on the application surface is checked
        private bool recordOn = false;
        private bool livePreviewOn = true;
        private bool seatedOn = true;

        // Bolean variables which indicate if the streams are activated or deactivated
        private bool colorStreamOn = false;
        private bool depthStreamOn = false;
        private bool skeletonStreamOn = false;
        private bool audioStreamOn = false;

        // Boolean variables to know what should be tracked, used inside methods
        private bool trackingBodyLanguageOn = false;
        private bool trackingSlidesOn = false;
        private bool trackingOn;

        // Boolean variables which are set on the UI and indicates what should be tracked
        private bool trackBodyLanguage = true;
        private bool trackSlides = true;
        private bool trackingOralCommunicationOn = true;


        // Counter how many frames were saved
        private int totalNumberofColorFrames;
        private int totalNumberofDepthFrames;
        private int totalNumberofSkeletonFrames;

        // Preview variables
        private int counterPreviewFramesColor = 0;
        private int counterPreviewFramesDepth = 0;
        private int counterPreviewFramesSkeleton = 0;
        public static int numberOfPreviewFrames = 1;

        // Variables needed to calculate the rectangle
        private int loopCalculatePixelChangeEndHight;
        private int distanceFromLoopStartToFarthestPoint;
        private int distanceFromLoopEndToFarthestPoint;
        private int distanceFromHipOldtoHipNew;

        private int loopStartCoordinate;
        private int loopEndCoordinate;

        // Definition of the DB name
        private string databaseName = "database";
        private SQLiteConnection databaseConnection;

        private EvaluationWindow evaluationWindow;
        private PropertiesWindow propertiesWindow;


        // Frame properties
        public static int colorFrameWidth;
        public static int colorFrameHeight;

        private int counterToTakeSnapshots;

        //********************************************//
        //************    Body Language   ************//
        //********************************************//

        private int skeletonID;

        //Tracking viewing direction
        private ViewingDirectionManager viewingDirectionManager;
        private SQLiteConnection databaseConnectionViewingDirectionManager;

        //Tracking movement
        private MovementManager movementManager;
        private SQLiteConnection databaseConnectionMovementManager;

        //Tracking gestures
        private GesturesManager gesturesManager;

        private SQLiteConnection databaseConnectionGesturesManager;

        private Vector2 coordinateColorLeftHand;
        private Vector2 coordinateColorRightHand;

        private Vector2 coordinateColorHipCenter;
        private Vector2 coordinateColorleftShoulder;
        private Vector2 coordinateColorRightShoulder;


        //********************************************//
        //************      Slides        ************//
        //********************************************//

        //Tracking slides
        private SlidesManager slidesManager;

        private SQLiteConnection databaseConnectionSlidesManager;
        public bool takeSnapshotOn = false;



        //********************************************//
        //******    Oral Communication        ********//
        //********************************************//
        private SQLiteConnection databaseConnectionOralCommunicationManager;


        //Replay variables
        Skeleton[] skeletonReplay;
        private SpeechRecognitionManager speechManager;
 

       




        #endregion Member Variables


        //********************************************//
        //************ Region Constructor ************//
        //********************************************//
        #region Constructor

        public MainWindow()
        {
                // Read properties XML file to load the properties
                XMLproperties.readPropertiesFromXML();

                InitializeComponent();
        }
        #endregion Constructor


        //********************************************//
        //************ Window_Loaded *****************//
        //********************************************//

        /// <summary>
        /// This method is opened when in the constructor MainWindow() the method InitializeComponent() is invoked.
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void MainWindow_Loaded(object sender, EventArgs e)
        {
            try
            {
                //listen to Kinect status changes
                KinectSensor.KinectSensors.StatusChanged += KinectSensors_StatusChanged;

                //iterrate through all connected sensors and use the first which has as status connected
                foreach (KinectSensor kinect in KinectSensor.KinectSensors)
                {
                    if (kinect.Status == KinectStatus.Connected)
                    {
                        _kinectSensor = kinect;
                        break;
                    }
                }

                if (KinectSensor.KinectSensors.Count == 0)
                {
                    MessageBox.Show("No Kinect found");
                }


                // Check if the directory for the snapshots exist, if not create the directory

                if (!Directory.Exists("Snapshots"))
                {
                    MessageBox.Show("Directory Snapshots created");
                    Directory.CreateDirectory("Snapshots");
                }

                // Initialization will be executed anyways, in case you only want to 
                // play previously saved videos
                startStreamKinectSensor();
            }

            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }


        #region ScaleValue Depdency Property
        public static readonly DependencyProperty ScaleValueProperty = DependencyProperty.Register("ScaleValue", typeof(double), typeof(MainWindow), new UIPropertyMetadata(1.0, new PropertyChangedCallback(OnScaleValueChanged), new CoerceValueCallback(OnCoerceScaleValue)));
        private int countHowLongOnLeftSide;
        private int countHowLongOnRightSide;
        private FileStream recordFileStream;
        private BufferedStream recordBufferedStream;

        private static object OnCoerceScaleValue(DependencyObject o, object value)
        {
            MainWindow mainWindow = o as MainWindow;
            if (mainWindow != null)
                return mainWindow.OnCoerceScaleValue((double)value);
            else
                return value;
        }

        private static void OnScaleValueChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            MainWindow mainWindow = o as MainWindow;
            if (mainWindow != null)
                mainWindow.OnScaleValueChanged((double)e.OldValue, (double)e.NewValue);
        }

        protected virtual double OnCoerceScaleValue(double value)
        {
            if (double.IsNaN(value))
                return 1.0f;

            value = Math.Max(0.1, value);
            return value;
        }

        protected virtual void OnScaleValueChanged(double oldValue, double newValue)
        {

        }

        public double ScaleValue
        {
            get
            {
                return (double)GetValue(ScaleValueProperty);
            }
            set
            {
                SetValue(ScaleValueProperty, value);
            }
        }
        #endregion

        private void MainGrid_SizeChanged(object sender, EventArgs e)
        {
            CalculateScale();
        }

        private void CalculateScale()
        {
            double yScale = ActualHeight / 750f;
            double xScale = ActualWidth / 1300f;
            double value = Math.Min(xScale, yScale);
            ScaleValue = (double)OnCoerceScaleValue(MainGrid, value);
        }



        private void KinectSensors_StatusChanged(object sender, StatusChangedEventArgs e)
        {
            switch (e.Status)
            {
                //First case indicates the Kinect is connected 
                case KinectStatus.Connected:
                    if (this._kinectSensor == null)
                    {
                        this._kinectSensor = e.Sensor;
                    }
                    break;

                //Second case Kinect is not connected
                case KinectStatus.Disconnected:
                    if (this._kinectSensor == e.Sensor)
                    {
                        this._kinectSensor = null;
                        this._kinectSensor = KinectSensor.KinectSensors
                                                  .FirstOrDefault(x => x.Status == KinectStatus.Connected);
                        if (this._kinectSensor == null)
                        {
                            //Notify the user that the sensor is disconnected
                            MessageBox.Show("Kinect is disconnected");
                        }
                    }
                    break;

                //Kinect is not ready
                case KinectStatus.NotReady:
                    break;

                //Kinect has no power
                case KinectStatus.NotPowered:
                    if (this._kinectSensor == e.Sensor)
                    {
                        this._kinectSensor = null;
                        this._kinectSensor = KinectSensor.KinectSensors
                                                  .FirstOrDefault(x => x.Status == KinectStatus.Connected);
                        if (this._kinectSensor == null)
                        {
                            //Notify the user that the sensor in not powered
                            MessageBox.Show("Kinect is no longer powered");
                        }
                    }
                    break;

                //Default status
                default:
                    MessageBox.Show("Unhandled Status: " + e.Status);
                    break;
            }
        }


        ////////////////////////////////////////////////
        //        Method InitializeKinectSensor       //
        ////////////////////////////////////////////////
        private void startStreamKinectSensor()
        {

            ////////////////////////////////////////////////
            //               Color Image Stream           //
            ////////////////////////////////////////////////

            initializeColorStream();


            ////////////////////////////////////////////////
            //               Depth Stream                 //
            ////////////////////////////////////////////////

            initializeDepthStream();


            /////////////////////////////////////////////////
            //               Skeleton Stream               //
            /////////////////////////////////////////////////

            initializeSkeletonStream();

            // Kinect Sensor must be started before the initializeTracking(),
            // otherwise the audio cannot directly be started
            if (_kinectSensor != null)
            {
                // Start the sensor
                _kinectSensor.Start();
            }

            /////////////////////////////////////////////////
            //               Database                      //
            /////////////////////////////////////////////////
            initializeDB();


            /////////////////////////////////////////////////
            //               Tracking                      //
            /////////////////////////////////////////////////
            initializeTracking();

        }



        /////////////////////////////////////////////////
        //              EvaluationWindow               //
        /////////////////////////////////////////////////

        private void initializeEvaluationWindow()
        {
            evaluationWindow = new EvaluationWindow(databaseName);
        }




        ////////////////////////////////////////////////
        //               Database                     //
        ////////////////////////////////////////////////

        private void initializeDB()
        {
            // Returns true if the DB could be create, if not error message is returned.
            String returnValue = SqliteConnection.createDB(databaseName);

            if (returnValue != "true")
            {
                MessageBox.Show("Error creating Database" + returnValue);
            }

            // Open DB connection
            databaseConnection = SqliteConnection.openDBConnection(databaseName);
        }







        ////////////////////////////////////////////////
        //               Tracking                     //
        ////////////////////////////////////////////////


        private void initializeTracking()
        {
            databaseConnectionViewingDirectionManager = SqliteConnection.openDBConnection(databaseName);
            viewingDirectionManager = new ViewingDirectionManager(databaseConnectionViewingDirectionManager);

            databaseConnectionMovementManager = SqliteConnection.openDBConnection(databaseName);
            movementManager = new MovementManager(databaseConnectionMovementManager);

            databaseConnectionGesturesManager = SqliteConnection.openDBConnection(databaseName);
            gesturesManager = new GesturesManager(databaseConnectionGesturesManager);


            databaseConnectionSlidesManager = SqliteConnection.openDBConnection(databaseName);
            slidesManager = new SlidesManager(databaseConnectionSlidesManager, colorFrameWidth, colorFrameHeight);

            countHowLongOnRightSide = 0;
        }


        
        /// <summary>
        /// Set the start tracking capture time
        /// </summary>
        /// <param name="startedCaptureTime"></param>
        private void startTracking(DateTime startedCaptureTime)
        {
            // Defines the start of the capture, this is needed to idenitfy the series
            viewingDirectionManager.startedCaptureTime = startedCaptureTime;
            movementManager.startedCaptureTime = startedCaptureTime;
            gesturesManager.startedCaptureTime = startedCaptureTime;
            slidesManager.startedCaptureTime = startedCaptureTime;

            // Additional check if oral communication is tracked, ortherwise the manager is not created
            // and hence a null pointer exception occurs
            if(trackingOralCommunicationOn)
                speechManager.startedCaptureTime = startedCaptureTime;

            SqliteConnection.startedCaptureTime = startedCaptureTime;

        }


        /// <summary>
        /// Body language tracking
        /// </summary>
        /// <param name="skeletons"></param>
        private void trackingBodyLanguage(Skeleton skeletons)
        {
            viewingDirectionManager.doWork(skeletons);
            movementManager.doWork(skeletons);
            gesturesManager.doWork(skeletons);
        }

        /// <summary>
        /// Slides change tracking
        /// </summary>
        /// <param name="?"></param>
        private void trackingSlides(Skeleton skeletons)
        {
            // Map the coordinates of the joints to the coordinates of the color stream
            coordinateColorLeftHand = skeletonManager.getColorPoint(JointType.HandLeft, skeletons);
            coordinateColorRightHand = skeletonManager.getColorPoint(JointType.HandRight, skeletons);
            coordinateColorHipCenter = skeletonManager.getColorPoint(JointType.HipCenter, skeletons);
            coordinateColorleftShoulder = skeletonManager.getColorPoint(JointType.ShoulderLeft, skeletons);
            coordinateColorRightShoulder = skeletonManager.getColorPoint(JointType.ShoulderRight, skeletons);

            // Defines if the player is on the left or right side of the color frame.
            // If player is on the right side, the pixel change will only be analysed of the right side of the color frame
            setPixelRangeOfInterest(coordinateColorLeftHand, coordinateColorRightHand, 
                                    coordinateColorHipCenter, coordinateColorleftShoulder, coordinateColorRightShoulder);
        }





        
        ////////////////////////////////////////////////
        //               Depth Image Stream           //
        ////////////////////////////////////////////////

        /// <summary>
        /// Initializes the depth stream.
        /// Registers the event handler and displays the output on the screen.
        /// </summary>
        private void initializeDepthStream()
        {
            // create a new depthStream Manager object
            depthStreamManager = new DepthStreamManager();

            if (_kinectSensor != null)
            {
                //Define the resolution of the depth camera and the framerate
                _kinectSensor.DepthStream.Enable(DepthImageFormat.Resolution640x480Fps30);
            }

            //Assign the depthStreamManager output to the surface and display it
            DepthImageElement.DataContext = depthStreamManager;
        }

        /// <summary>
        /// Eventhandler of the depth stream.
        /// Copies the frame and send it to the depthStreamManager
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _kinectSensor_DepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)
        {
            using (DepthImageFrame depthFrame = e.OpenDepthImageFrame())
            {
                if (depthFrame == null)
                {
                    Console.WriteLine("_kinectSensor_DepthFrameReady: Depth Frame is empty");
                    return;
                }
                else
                {
                    counterPreviewFramesDepth++;

                    if ((counterPreviewFramesDepth == numberOfPreviewFrames) && livePreviewOn)
                    {
                        counterPreviewFramesDepth = 0;
                        //The depthFrame is sent to the update method of the depthStreamManager
                        depthStreamManager.update(depthFrame);
                    }

                    //This if checks if the check box on the application surface is checked
                    if (recordOn)
                    {
                        //Records the frames
                        recordDepthStreams.Record(depthFrame);
                    }
                }
            }
        }






        ////////////////////////////////////////////////
        //               Color Image Stream           //
        ////////////////////////////////////////////////

        /// <summary>
        /// Initializes the color stream.
        /// Registers the event handler and displays the output on the screen
        /// </summary>
        private void initializeColorStream()
        {
            // create a new coloStream Manager object
            colorStreamManager = new ColorStreamManager();

            if (_kinectSensor != null)
            { 
                ColorImageFormat colorImageFormat = ColorImageFormat.RgbResolution640x480Fps30;
                //Define the resolution of the color camera and the framerate
                _kinectSensor.ColorStream.Enable(colorImageFormat);
                colorFrameWidth = 640;
                colorFrameHeight = 480;

            }

            //Assign the colorStreamManager output to the surface and display it
            ColorImageElement.DataContext = colorStreamManager;


        }


        /// <summary>
        /// Eventhandler of the color stream.
        /// Copies the frame and send it to the ColorStreamManager
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        private void _kinectSensor_ColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
        {
            //Using calls the Dispose after the Using block is left!
            using (ColorImageFrame colorFrame = e.OpenColorImageFrame())
            {
                if (colorFrame == null)
                {
                    if (DEBUGon)
                        Console.WriteLine("_kinectSensor_ColorFrameReady: Color Frame is empty");
                    return;
                }
                else
                {
                    counterPreviewFramesColor++;

                    if ((counterPreviewFramesColor == numberOfPreviewFrames) && livePreviewOn)
                    {
                        counterPreviewFramesColor = 0;

                        //code below is necessary to display the frames on the application surface
                        //The colorFrame is sent to the update method of the colorStreamManager
                        colorStreamManager.update(colorFrame);

                    }


                    if (trackingSlidesOn)
                    {

                        byte[] currentColorFramePixels = new byte[colorFrame.PixelDataLength];
                        colorFrame.CopyPixelDataTo(currentColorFramePixels);

                        slidesManager.trackingSlides(currentColorFramePixels, colorFrame.PixelDataLength, colorFrame.Width, colorFrame.Height);

                    }



                    counterToTakeSnapshots++;

                    // depending on what is set in the properties, after the defined amount of seconds is a snapshot taken
                    if (((counterToTakeSnapshots >= XMLproperties.framesTillSnapshot) && takeSnapshotOn) && trackingOn)
                    {
                        counterToTakeSnapshots = 0;

                        takeSnapshot();
                    }


                    //This if checks if the check box on the application surface is checked
                    if (recordOn)
                    {
                        //Records the frames
                        recordColorStreams.Record(colorFrame);

                    }
                }
            }

        }



        

        ////////////////////////////////////////////////
        //               Skeleton Stream              //
        ////////////////////////////////////////////////

        /// <summary>
        /// Initializes the skeleton stream.
        /// Registers the event handler
        /// In contras to the depth and color stream, the skeletonManager gets the skeletonCanvas to display
        /// the output
        /// </summary>
        private void initializeSkeletonStream()
        {
            if (_kinectSensor != null)
            {
                //Enable the skeleton stream and transfer the smoothing parameters
                _kinectSensor.SkeletonStream.Enable(new TransformSmoothParameters
                                                    {
                                                        Smoothing = 0.7f,
                                                        Correction = 0.7f,
                                                        Prediction = 0.5f,
                                                        JitterRadius = 0.10f,
                                                        MaxDeviationRadius = 0.04f
          // Explanation of the values
          //http://msdn.microsoft.com/en-us/library/microsoft.kinect.transformsmoothparameters_properties.aspx                                                                            
                              /*                          Smoothing = 0.5f,
                                                        Correction = 0.5f,
                                                        Prediction = 0.5f,
                                                        JitterRadius = 0.05f,
                                                        MaxDeviationRadius = 0.04f
                               */   
                                                    });


                //Register skeleton event handler
                //                _kinectSensor.SkeletonFrameReady += _kinectSensor_SkeletonFrameReady;

                // Create the SkeletonDisplayManager object, transfer parameters are the kinect sensor 
                // and the canvas from the application surface to display the skeletons
                skeletonManager = new SkeletonDisplayManager(_kinectSensor, skeletonCanvas);
            }
            else
            {
                // if you want to play a saved stream withouth having a kinect connected
                // this else is used to create the SkeletonDisplayManager object withouth the 
                // transfer parameter _kinectSensor
                skeletonManager = new SkeletonDisplayManager(skeletonCanvas);
            }
        }


        /// <summary>
        /// Eventhandler of the skeleton stream.
        /// Copies the frame, gets the skeletons and draws them.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _kinectSensor_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
        {
            //copy the frame from e to the new created local variable skeletonFrame
            using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
            {
                if (skeletonFrame == null)
                {
                    if (DEBUGon)
                        Console.WriteLine("_kinectSensor_SkeletonFrameReady: Skeleton Frame is empty");
                    return;
                }
                else
                {

                    // gets the skeletons from the frame and saves it to an array of skeletons
                    SkeletonTools.GetSkeletons(skeletonFrame, ref skeletonsPreview);


                    // Find the first tracked skeleton and return the ID, if no tracked skeleton is found, return.
                    if ((skeletonID = getSkeletonID(skeletonsPreview)) == -1)
                        return;

                    counterPreviewFramesSkeleton++;

                    if ((counterPreviewFramesSkeleton == numberOfPreviewFrames) && livePreviewOn)
                    {
                        counterPreviewFramesSkeleton = 0;

                        // Executes the draw method and transfers the skeletons, dependent if seated mode is on or off
                        if (seatedOn)
                        {
                            skeletonManager.drawNoLegs(skeletonsPreview[skeletonID]);
                        }
                        else
                        {
                            skeletonManager.draw(skeletonsPreview[skeletonID]);
                        }

                    }


                    if (trackingSlidesOn)
                    {
                        // Track the slide changes
                        trackingSlides(skeletonsPreview[skeletonID]);
                    }

                    if (trackingBodyLanguageOn)
                    {
                        // Only the first recognized skeleton is tracked!
                        trackingBodyLanguage(skeletonsPreview[skeletonID]);
                    }


                    //This if checks if the check box on the application surface is checked
                    if (recordOn)
                    {
                        totalNumberofSkeletonFrames++;

                        //Records the frames
                        recordSkeletonStreams.Record(skeletonFrame);
                    }
                }
            }
//            Console.WriteLine("Time needed for color method: " + DateTime.Now.Subtract(timeBefore));
        }








        ////////////////////////////////////////////////
        //               Record Stream                //
        ////////////////////////////////////////////////




        /// <summary>
        /// If the checkbox on the application surface is clicked, the recording is started or stopped
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// 
        private void recordStreamBTN_Click(object sender, RoutedEventArgs e)
        {
            if (!recordOn)
            {
                // Open file open dialog to select where the record should be saved
                SaveFileDialog saveFileDialog = new SaveFileDialog
                {
                    Title = "Select filename",
                    Filter = "Replay files|*.replay"
                };
                if (saveFileDialog.ShowDialog() == true)
                {
                    //Create a Filestream
                    try
                    {
                        // Create a file stream, file will be created and readwrite permissions
                        recordFileStream = new FileStream(saveFileDialog.FileName, FileMode.Create, FileAccess.ReadWrite);
                        recordBufferedStream = new BufferedStream(recordFileStream);

                        // Create a file stream, based on the filename for the video stream
                        fsAudio = new FileStream(saveFileDialog.FileName + "_audio.wav", FileMode.Create, FileAccess.ReadWrite);
                        bsAudio = new BufferedStream(fsAudio);

                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                }


                if (colorStreamOn)
                {
                    // Create color record object
                    recordColorStreams = new RecordStreams(DetectingKinectSencor.RecordStreams.KinectRecordOptions.Color, recordBufferedStream);
                }

                if (depthStreamOn)
                {
                    // Create depth record object
                    recordDepthStreams = new RecordStreams(DetectingKinectSencor.RecordStreams.KinectRecordOptions.Depth, recordBufferedStream);
                }

                if (skeletonStreamOn)
                {
                    // Create skeleton record object
                    recordSkeletonStreams = new RecordStreams(DetectingKinectSencor.RecordStreams.KinectRecordOptions.Skeletons, recordBufferedStream);
                }

                if (audioStreamOn)
                {
                    audioSource = _kinectSensor.AudioSource;

                    // Create audio record object
                    recordAudioStream = new RecordAudioStream(bsAudio, audioSource);

                    //Starts recording the streams
                    recordAudioStream.reading = true;
                }
                recordOn = true;

                // This variable is checked, in the event handler method which is fired when there is a new frame
                // if the variable is true, the stream is saved
                totalNumberofColorFrames = 0;
                totalNumberofDepthFrames = 0;
                totalNumberofSkeletonFrames = 0;
            }
            else
            {
                MessageBox.Show("Record already started");
            }
        }





        ////////////////////////////////////////////////
        //               Play stream                  //
        ////////////////////////////////////////////////


        /// <summary>
        /// Button to play previously saved streams
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void playBTN_Click(object sender, RoutedEventArgs e)
        {

            //The filename is used from the text field on the application surface
            //  string fileName = fileNameTxt.Text;

            OpenFileDialog openFileDialog = new OpenFileDialog
            {
                Title = "Select filename",
                Filter = "Replay files|*.replay"
            };
            if (openFileDialog.ShowDialog() == true)
            {
                Stream replayAudioStream = null;
                Stream replayVideoStream = null;

                try
                {
                    // Create source stream for the video 
                    replayVideoStream = File.OpenRead(openFileDialog.FileName);
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Can't open file: " + ex.Message);
                }

                try
                {
                    replayAudioStream = File.OpenRead(openFileDialog.FileName + "_audio.wav");
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Audio file not found: " + ex.Message);
                }


                // Create source stream for the audio
                audioPlayer.Source = new Uri(openFileDialog.FileName + "_audio.wav");
                audioPlayer.LoadedBehavior = MediaState.Manual;
                audioPlayer.UnloadedBehavior = MediaState.Manual;


                // In case only audio was recorded the replay VideoStream.length is zero
                if (replayVideoStream.Length > 0)
                {
                    replay = new PlayStreams(replayVideoStream, this);


                    replay.ColorImageFrameReady += replay_ColorImageFrameReady;
                    replay.DepthImageFrameReady += replay_DepthImageFrameReady;
                    replay.SkeletonFrameReady += replay_SkeletonImageFrameReady;


                    // As soon as the frames raise a property change in the colorStreamManager the output is 
                    // displayed on the application surface 
                    ColorImageElement.DataContext = colorStreamManager;

                    // As soon as the frames raise a property change in the depthStreamManager the output is 
                    // displayed on the application surface 
                    DepthImageElement.DataContext = depthStreamManager;

                    // Skeleton das not Update the DataContext, it draws directly on the application surface

                    startTracking();

 //                   copyTimeStamps(ref replay.skeletonReplay.frames, replay.colorReplay.frames);


                    replay.Start();
                }

                if (audioStreamOn)
                {
                    // Starts the audio replay when all frames were added to the list
                    startAudioReplay(replayAudioStream);
                }


            }
        }






        /// <summary>
        /// Starts audio replay
        /// </summary>
        private void startAudioReplay(Stream replayAudioStream)
        {
            //            speechManager = new SpeechRecognitionManager(replayAudioStream);
            audioPlayer.Play();
        }

        /// <summary>
        /// Method which is fired as soon as a now colorImageFrame is ready
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void replay_ColorImageFrameReady(object sender, Kinect.Toolbox.Record.PlayStreams.PlayColorStreamEventArgs e)
        {
            counterPreviewFramesColor++;

            if (counterPreviewFramesColor == numberOfPreviewFrames)
            {
                counterPreviewFramesColor = 0;


                colorStreamManager.update(e.ColorImageFrame);

            }


            if (trackingSlidesOn)
            {

                // Here is the pixel range of interest set, such as if the player is on the left or right
                byte[] currentColorFramePixels = new byte[e.ColorImageFrame.PixelDataLength];
                e.ColorImageFrame.CopyPixelDataTo(currentColorFramePixels);

                slidesManager.trackingSlides(currentColorFramePixels,
                                             e.ColorImageFrame.PixelDataLength,
                                             e.ColorImageFrame.Width,
                                             e.ColorImageFrame.Height);

            }
        }

        /// <summary>
        /// Method which is fired as soon as a now depthImageFrame is ready
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void replay_DepthImageFrameReady(object sender, Kinect.Toolbox.Record.PlayStreams.PlayDepthStreamEventArgs e)
        {
            counterPreviewFramesDepth++;

            if (counterPreviewFramesDepth == numberOfPreviewFrames)
            {
                counterPreviewFramesDepth = 0;

                depthStreamManager.update(e.DepthImageFrame);

            }
        }


        /// <summary>
        /// Method which is fired as soon as a now skeletonImageFrame is ready
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void replay_SkeletonImageFrameReady(object sender, Kinect.Toolbox.Record.PlayStreams.PlaySkeletonStreamEventArgs e)
        {
            skeletonReplay = e.SkeletonFrame.Skeletons;


            // Detect if the sekeleton is null
            if (skeletonReplay == null)
            {
                Console.WriteLine("Skeleton frame empty");
                return;
            }

            if ((skeletonID = getSkeletonID(skeletonReplay)) == -1)
            {
                Console.WriteLine("No skeleton tracked");
                return;
            }

            


            counterPreviewFramesSkeleton++;

            if (counterPreviewFramesSkeleton == numberOfPreviewFrames)
            {
                counterPreviewFramesSkeleton = 0;

                // Check if seated is on
                if (seatedOn)                
                {
                    skeletonManager.drawNoLegs(skeletonReplay[skeletonID]);
                }
                else
                {
                    skeletonManager.draw(skeletonReplay[skeletonID]);
                }
            }

            

            // Body language is tracked
            if (trackingBodyLanguageOn)
            {
                try
                {
                    trackingBodyLanguage(skeletonReplay[skeletonID]);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Error in tracking: " + ex.Message);
                }
            }



            if (trackingSlidesOn)
            {
                // Track the slide changes, based on the set range of interest
                trackingSlides(skeletonReplay[skeletonID]);
            }
        }


        /// <summary>
        /// Returns the first ID of the skeleton which is tracked. 
        /// The zero ID is usually a wrong tracked skeleton anywhere in the room, so start from one.
        /// </summary>
        /// <param name="skeletonReplay"></param>
        /// <returns></returns>
        private int getSkeletonID(Skeleton[] skeletonReplay)
        {
            int skeletonID = -1;
            float closestDistance = 30000f;

            // SkeletonReplay is a array of the size of 6 elements (max number of tracked skeletons, 2 max at the same time)
            // need to loop through the array to find the skeleton which is at the moment tracked
            // in case two people are tracked only the first detected skeleton is used

            for (int i = 0; i < skeletonReplay.Length; i++)
            {
                if (skeletonReplay[i].TrackingState == SkeletonTrackingState.Tracked 
                    &&
                    skeletonReplay[i].Position.Z < closestDistance)
                {

                    skeletonID = i;
                    closestDistance = skeletonReplay[i].Position.Z;
                }
            }
            return skeletonID;
        }

        /// <summary>
        /// Returns the first ID of the skeleton which is tracked. 
        /// The zero ID is usually a wrong tracked skeleton anywhere in the room, so start from one.
        /// </summary>
        /// <param name="skeletonReplay"></param>
        /// <returns></returns>
        private int getSkeletonID(Skeleton[] skeletonReplay, int previousSkeletonID, int startPoint)
        {
            int skeletonID = -1;

            // SkeletonReplay is a array of the size of 6 elements (max number of tracked skeletons, 2 max at the same time)
            // need to loop through the array to find the skeleton which is at the moment tracked
            // in case two people are tracked only the first detected skeleton is used
            for (int i = startPoint; i < skeletonReplay.Length; i++)
            {
                if (skeletonReplay[i].TrackingState == SkeletonTrackingState.Tracked && skeletonReplay[i].TrackingId != previousSkeletonID)
                {
                    skeletonID = i;
                    break;
                }
            }
            return skeletonID;
        }


        /// <summary>
        /// This method turns the live preview on or off
        /// this allows to save the stream but not preview it on the application surface
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void livePreviewCHK_Click(object sender, RoutedEventArgs e)
        {
            if (livePreviewCHK.IsChecked.HasValue && livePreviewCHK.IsChecked.Value)
            {
                livePreviewOn = true;
            }
            else
            {
                livePreviewOn = false;
            }
        }


        /// <summary>
        /// Changes to the seated mode, only the arms and head of the skeleton are drawn
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void seatedCHK_Click(object sender, RoutedEventArgs e)
        {
            if (seatedCHK.IsChecked.HasValue && seatedCHK.IsChecked.Value)
            {
                seatedOn = true;
            }
            else
            {
                seatedOn = false;
            }
        }


        /// <summary>
        /// Stops the replay and the recording
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void stopReplayBTN_Click(object sender, RoutedEventArgs e)
        {
            if (replay != null)
                replay.Stop();

            try
            {
                if (audioPlayer != null)
                    audioPlayer.Stop();
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error can not stop audio player: " + ex.Message);
            }

            if (recordOn)
            {
                recordOn = false;

                // Write the total number of recorded frames
                Console.WriteLine("Recorded color frames: " + totalNumberofColorFrames);
                Console.WriteLine("Recorded depth frames: " + totalNumberofDepthFrames);
                Console.WriteLine("Recorded skeleton frames: " + totalNumberofSkeletonFrames);

                // Stop the audio recording thread
                if (recordAudioStream != null)
                    recordAudioStream.stopAudioRecording();


                //Close file stream
                if (recordFileStream != null)
                    recordFileStream.Close();
  
                //Stops recording
                if (recordDepthStreams != null)
                    recordDepthStreams.Stop();
                if (recordColorStreams != null)
                    recordColorStreams.Stop();
                if (recordSkeletonStreams != null)
                    recordSkeletonStreams.Stop();
            }

            if (trackingOn)
            {
                stopTracking();
            }
        }

        /// <summary>
        /// Registers or unregisters the colorStream event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void colorCHK_Click(object sender, RoutedEventArgs e)
        {
            if (colorCHK.IsChecked.HasValue && colorCHK.IsChecked.Value)
            {
                colorStreamOn = true;
                //Register color event handler
                _kinectSensor.ColorFrameReady += _kinectSensor_ColorFrameReady;
            }
            else
            {
                colorStreamOn = false;
                //Unregister color event handler
                _kinectSensor.ColorFrameReady -= _kinectSensor_ColorFrameReady;
            }
        }


        /// <summary>
        /// Registers or unregisters the depthStream event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void depthCHK_Click(object sender, RoutedEventArgs e)
        {
            if (depthCHK.IsChecked.HasValue && depthCHK.IsChecked.Value)
            {
                depthStreamOn = true;

                //Register depth event handler
                _kinectSensor.DepthFrameReady += _kinectSensor_DepthFrameReady;
            }
            else
            {
                depthStreamOn = false;
                //Unregister depth event handler
                _kinectSensor.DepthFrameReady -= _kinectSensor_DepthFrameReady;
            }
        }

        /// <summary>
        /// Registers or unregisters the skeletonStream event handler
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void skeletonCHK_Click(object sender, RoutedEventArgs e)
        {
            if (skeletonCHK.IsChecked.HasValue && skeletonCHK.IsChecked.Value)
            {
                skeletonStreamOn = true;
                //Register skeleton event handler
                _kinectSensor.SkeletonFrameReady += _kinectSensor_SkeletonFrameReady;
            }
            else
            {
                skeletonStreamOn = false;
                //Unregister skeleton event handler
                _kinectSensor.SkeletonFrameReady -= _kinectSensor_SkeletonFrameReady;
            }
        }

        private void audioCHK_Click(object sender, RoutedEventArgs e)
        {
            if (audioCHK.IsChecked.HasValue && audioCHK.IsChecked.Value)
            {
                audioStreamOn = true;
            }
            else
            {
                if (audioSource != null)
                    _kinectSensor.AudioSource.Stop();
                audioStreamOn = false;
            }
        }

        /// <summary>
        /// Defines the number of preview frames, every frame, every 5th, every 15th, every 30th
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void numberOfPreviewFramesCOB_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            switch (numberOfPreviewFramesCOB.SelectedIndex)
            {
                case 0:
                    MainWindow.numberOfPreviewFrames = 1;
                    counterPreviewFramesColor = 0;
                    counterPreviewFramesDepth = 0;
                    counterPreviewFramesSkeleton = 0;
                    break;

                case 1:
                    MainWindow.numberOfPreviewFrames = 2;
                    counterPreviewFramesColor = 0;
                    counterPreviewFramesDepth = 0;
                    counterPreviewFramesSkeleton = 0;
                    break;

                case 2:
                    MainWindow.numberOfPreviewFrames = 3;
                    counterPreviewFramesColor = 0;
                    counterPreviewFramesDepth = 0;
                    counterPreviewFramesSkeleton = 0;
                    break;

                case 3:
                    MainWindow.numberOfPreviewFrames = 5;
                    counterPreviewFramesColor = 0;
                    counterPreviewFramesDepth = 0;
                    counterPreviewFramesSkeleton = 0;
                    break;

                case 4:
                    MainWindow.numberOfPreviewFrames = 15;
                    counterPreviewFramesColor = 0;
                    counterPreviewFramesDepth = 0;
                    counterPreviewFramesSkeleton = 0;
                    break;
                case 5:
                    MainWindow.numberOfPreviewFrames = 30;
                    counterPreviewFramesColor = 0;
                    counterPreviewFramesDepth = 0;
                    counterPreviewFramesSkeleton = 0;
                    break;
            }
        }









        ////////////////////////////////////////////////
        //            Start Tracking Button           //
        ////////////////////////////////////////////////




        private void startTrackingBTN_Click(object sender, RoutedEventArgs e)
        {
            startTracking();
        }

        private void startTracking()
        {
            if (!trackingOn)
            {
                trackingOn = true;

                DateTime startedCaptureTime = DateTime.Now;

                if (trackBodyLanguage)
                {
                    // Starts the tracking  in the skeletonReadyEvent is now the if true
                    trackingBodyLanguageOn = true;
                }

                if (trackSlides)
                {
                    // Starts the tracking  in the skeletonReadyEvent is now the if true
                    trackingSlidesOn = true;
                }

                if (trackingOralCommunicationOn)
                {
                    databaseConnectionOralCommunicationManager = SqliteConnection.openDBConnection(databaseName);
                    speechManager = new SpeechRecognitionManager(_kinectSensor, databaseConnectionOralCommunicationManager);
                }

                // Saves the startingpoint into the DB
                startTracking(startedCaptureTime);

            }
            else
            {
                MessageBox.Show("Tracking already started");
            }
            
        }

        private void stopTrackingBTN_Click(object sender, RoutedEventArgs e)
        {
            stopTracking();
        }

        private void stopTracking()
        {
            if (trackingOn)
            {
                DateTime stoppedCaptureTime = DateTime.Now;

                trackingOn = false;

                trackingBodyLanguageOn = false;
                trackingSlidesOn = false; 


                if (trackingOralCommunicationOn && speechManager != null)
                {
                    speechManager.stopRecognition();

                    trackingOralCommunicationOn = false;
                }


                // Save the startCaptureTime in the DB
                SqliteConnection.saveCaptureTime(databaseConnection, stoppedCaptureTime);

            }
            else
            {
                MessageBox.Show("Tracking not started yet");
            }
        }


        private void evaluationBTN_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                // Initialize the evaluation window
                initializeEvaluationWindow();

                evaluationWindow.Show();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error evaluation window: " + ex.Message);
            }
        }


        ////////////////////////////////////////////////
        //              Shutdown Button               //
        ////////////////////////////////////////////////


        /// <summary>
        /// Executed when on the application the shutdown button is pressed.
        /// Uninitializes the sensor, stops the recording, closes the file stream.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ShutdownBTN_Click(object sender, RoutedEventArgs e)
        {
            uninitializeKinectSensor();
        }

        /// <summary>
        /// Method to uninitialize the kinect sensor and stop everything
        /// </summary>
        private void uninitializeKinectSensor()
        {
            //Turn everything off
            recordOn = false;
            livePreviewOn = false;
            seatedOn = false;
            colorStreamOn = false;
            depthStreamOn = false;
            skeletonStreamOn = false;
            audioStreamOn = false;


            if (_kinectSensor != null)
            {
                _kinectSensor.Stop();

                try
                {
                    // Removes the event handler
                    _kinectSensor.ColorFrameReady -= _kinectSensor_ColorFrameReady;
                    _kinectSensor.DepthFrameReady -= _kinectSensor_DepthFrameReady;
                    _kinectSensor.SkeletonFrameReady -= _kinectSensor_SkeletonFrameReady;

                    if (databaseConnection != null)
                        SqliteConnection.closeConnection(databaseConnection);

                    if (databaseConnectionViewingDirectionManager != null)
                        SqliteConnection.closeConnection(databaseConnectionViewingDirectionManager);

                    if (databaseConnectionGesturesManager != null)
                        SqliteConnection.closeConnection(databaseConnectionGesturesManager);

                    if (databaseConnectionMovementManager != null)
                        SqliteConnection.closeConnection(databaseConnectionMovementManager);


                    // Stops recording
                    if (recordDepthStreams != null)
                        recordDepthStreams.Stop();
                    if (recordColorStreams != null)
                        recordColorStreams.Stop();
                    if (recordSkeletonStreams != null)
                        recordSkeletonStreams.Stop();

                    // Close audio file stream
                    if (bsAudio != null)
                        bsAudio.Close();

                    if (fsAudio != null)
                        fsAudio.Close();

                    // Close video file stream
                    if (recordBufferedStream != null)
                        recordBufferedStream.Close();

                    if (recordFileStream != null)
                        recordFileStream.Close();

                    if (trackingOn)
                    {
                        stopTracking();
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
            Environment.Exit(0);
        }


        /// <summary>
        /// Defines if the speaker is on the left or the right side
        /// </summary>
        /// <param name="coordinateColorLeftHand"></param>
        /// <param name="coordinateColorRightHand"></param>
        /// <param name="coordinateColorHipCenter"></param>
        /// <param name="coordinateColorLeftShoulder"></param>
        /// <param name="coordinateColorRightShoulder"></param>
        private void setPixelRangeOfInterest(Vector2 coordinateColorLeftHand, Vector2 coordinateColorRightHand, 
                                             Vector2 coordinateColorHipCenter,  Vector2 coordinateColorLeftShoulder, 
                                             Vector2 coordinateColorRightShoulder)
        {

            // If the speaker was on the left or on the right side, for 10 seconds than use this side till end of presentation
            if ((countHowLongOnRightSide > (30 * 10)) || (countHowLongOnLeftSide > (30 * 10)))
            {
                if (countHowLongOnRightSide > countHowLongOnLeftSide)
                {
                    setValuesForspeakerOnTheRightSide(ref coordinateColorRightHand, ref coordinateColorRightShoulder);
                }
                else
                {
                    setValuesForSpeakerOnTheLeftSide(ref coordinateColorLeftHand, ref coordinateColorLeftShoulder);
                }
            }
            else
            {
                // If the the distance from the starting point to the hip center is smaller than the distance
                //  to the frame width.
                // speaker is on the right side
                if (((0 + coordinateColorHipCenter.X) <= (colorFrameWidth - coordinateColorHipCenter.X)))
                {
                    //Count how often on right side
                    countHowLongOnRightSide++;
                    setValuesForspeakerOnTheRightSide(ref coordinateColorRightHand, ref coordinateColorRightShoulder);
                }
                // Speaker is on the right side
                else
                {
                    //Count how often on left side
                    countHowLongOnLeftSide++;
                    setValuesForSpeakerOnTheLeftSide(ref coordinateColorLeftHand, ref coordinateColorLeftShoulder);
                }
            }


            // Add the offset to the hip
            loopCalculatePixelChangeEndHight = (int)coordinateColorHipCenter.Y - XMLproperties.offsetHipSkeletonPosition;


            distanceFromHipOldtoHipNew = Math.Abs(loopCalculatePixelChangeEndHight - slidesManager.loopCalculatePixelChangeEndHight);

            // if the new y coordinate is higher then the old with the offset, than update
            if (loopCalculatePixelChangeEndHight <= slidesManager.loopCalculatePixelChangeEndHight)
            {
                // Sets the max hight, usually the projection is higher than the hip center.
                SkeletonDisplayManager.farthesPointHipY = loopCalculatePixelChangeEndHight;
                slidesManager.loopCalculatePixelChangeEndHight = loopCalculatePixelChangeEndHight;
            }
            else
            {
                if (distanceFromHipOldtoHipNew >= XMLproperties.thresholdDistanceFromHipOldtoHipNew)
                {
                    loopCalculatePixelChangeEndHight += distanceFromHipOldtoHipNew >> 1;

                    // Sets the max hight, usually the projection is higher than the hip center.
                    SkeletonDisplayManager.farthesPointHipY = loopCalculatePixelChangeEndHight;
                    slidesManager.loopCalculatePixelChangeEndHight = loopCalculatePixelChangeEndHight;
                }
            }
        }

        /// <summary>
        /// The speaker is on the left side
        /// </summary>
        /// <param name="coordinateColorLeftHand"></param>
        /// <param name="coordinateColorLeftShoulder"></param>
        private void setValuesForSpeakerOnTheLeftSide(ref Vector2 coordinateColorLeftHand, ref Vector2 coordinateColorLeftShoulder)
        {
            if (coordinateColorLeftShoulder.X <= coordinateColorLeftHand.X)
            {
                // Mines buffer because speaker is on the right side, thus the start point needs to 
                // be nearer to the left side
                loopEndCoordinate = (int)coordinateColorLeftShoulder.X - XMLproperties.offsetSkeletonPosition;
            }
            else
            {
                loopEndCoordinate = (int)coordinateColorLeftHand.X - XMLproperties.offsetSkeletonPosition;
            }

            distanceFromLoopEndToFarthestPoint = Math.Abs(loopEndCoordinate - slidesManager.loopCalculatePixelChangeEnd);

            if (loopEndCoordinate <= slidesManager.loopCalculatePixelChangeEnd)
            {
                SkeletonDisplayManager.speakerOnRightSide = true;
                SkeletonDisplayManager.farthesPointLeftX = loopEndCoordinate;

                slidesManager.speakerOnTheRightSide = true;
                slidesManager.loopCalculatePixelChangeStart = 0;
                slidesManager.loopCalculatePixelChangeEnd = loopEndCoordinate;
            }
            else
            {
                // if the distance exceees a certain threshold the loopend is decremented
                // by the half of the distance
                if (distanceFromLoopEndToFarthestPoint >= XMLproperties.thresholdChangeBorderOfRectangle)
                {
                    loopEndCoordinate -= distanceFromLoopEndToFarthestPoint >> 1;

                    SkeletonDisplayManager.speakerOnRightSide = true;
                    SkeletonDisplayManager.farthesPointLeftX = loopEndCoordinate;

                    slidesManager.speakerOnTheRightSide = true;
                    slidesManager.loopCalculatePixelChangeStart = 0;
                    slidesManager.loopCalculatePixelChangeEnd = loopEndCoordinate;
                }
            }
        }

        /// <summary>
        /// The speaker is on the right side
        /// </summary>
        /// <param name="coordinateColorRightHand"></param>
        /// <param name="coordinateColorRightShoulder"></param>
        private void setValuesForspeakerOnTheRightSide(ref Vector2 coordinateColorRightHand, ref Vector2 coordinateColorRightShoulder)
        {
            // Get the farthest away joint of the body
            if (coordinateColorRightShoulder.X <= coordinateColorRightHand.X)
            {
                // Buffer, because coordinates of the joints are always the center coordinates
                loopStartCoordinate = (int)coordinateColorRightHand.X + XMLproperties.offsetSkeletonPosition;
            }
            else
            {
                loopStartCoordinate = (int)coordinateColorRightShoulder.X + XMLproperties.offsetSkeletonPosition;
            }

            distanceFromLoopStartToFarthestPoint = Math.Abs(loopStartCoordinate - slidesManager.loopCalculatePixelChangeStart);

            if (loopStartCoordinate >= slidesManager.loopCalculatePixelChangeStart)
            {
                SkeletonDisplayManager.speakerOnRightSide = false;

                SkeletonDisplayManager.farthesPointRightX = loopStartCoordinate;

                slidesManager.speakerOnTheRightSide = false;
                slidesManager.loopCalculatePixelChangeStart = loopStartCoordinate;
                slidesManager.loopCalculatePixelChangeEnd = colorFrameWidth;
            }
            else
            {
                if (distanceFromLoopStartToFarthestPoint >= XMLproperties.thresholdChangeBorderOfRectangle)
                {
                    loopStartCoordinate += distanceFromLoopStartToFarthestPoint >> 1;

                    SkeletonDisplayManager.speakerOnRightSide = false;

                    SkeletonDisplayManager.farthesPointRightX = loopStartCoordinate;

                    slidesManager.speakerOnTheRightSide = false;
                    slidesManager.loopCalculatePixelChangeStart = loopStartCoordinate;
                    slidesManager.loopCalculatePixelChangeEnd = colorFrameWidth;
                }
            }
        }



        private void changePropertiesBTN_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                // Initialize the properties window
                initializePropertiesWindow();
                propertiesWindow.initializeProperties();

                propertiesWindow.Show();
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error properties window: " + ex.Message);
            }
        }

        private void initializePropertiesWindow()
        {
            propertiesWindow = new PropertiesWindow();
        }


        private void bodyLanguageCHK_Click(object sender, RoutedEventArgs e)
        {
            if (bodyLanguageCHK.IsChecked.HasValue && bodyLanguageCHK.IsChecked.Value)
            {
                trackBodyLanguage = true;
            }
            else
            {
                trackBodyLanguage = false;
            }

        }

        private void slidesCHK_Click(object sender, RoutedEventArgs e)
        {
            if (slidesCHK.IsChecked.HasValue && slidesCHK.IsChecked.Value)
            {
                trackSlides = true;
            }
            else
            {
                trackSlides = false;
            }
        }


        private void takeSnapshotsCHK_Click(object sender, RoutedEventArgs e)
        {
            if (takeSnapshotsCHK.IsChecked.HasValue && takeSnapshotsCHK.IsChecked.Value)
            {
                takeSnapshotOn = true;
            }
            else
            {
                takeSnapshotOn = false;
            }
        }

        private void oralCommunicationCHK_Click(object sender, RoutedEventArgs e)
        {
            if (oralCommunicationCHK.IsChecked.HasValue && oralCommunicationCHK.IsChecked.Value)
            {
                trackingOralCommunicationOn = true;
            }
            else
            {
                trackingOralCommunicationOn = false;
            }
        }

        /// <summary>
        /// Method to take snapshots of the previewed frame
        /// </summary>
        public void takeSnapshot()
        {
            string fileName = DateTime.Now.ToString(Clock.datetimeFormatForFilePath);

            try
            {
                using (FileStream savedSnapshot = new FileStream("Snapshots\\" + fileName + ".jpg", FileMode.CreateNew))
                {
                    if (File.Exists(fileName))
                    {
                        return;
                    }

                    BitmapSource image = (BitmapSource)ColorImageElement.Source;

                    JpegBitmapEncoder jpgEncoder = new JpegBitmapEncoder();

                    jpgEncoder.QualityLevel = 70;

                    jpgEncoder.Frames.Add(BitmapFrame.Create(image));

                    jpgEncoder.Save(savedSnapshot);

                    savedSnapshot.Flush();
                    savedSnapshot.Close();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Error in take snapshot" + e.Message);
            }
        }


        /// <summary>
        /// Method to take snapshots of the previewed frame
        /// </summary>
        public void takeSnapshot(int frameNumber)
        {
            string fileName = frameNumber.ToString();

            try
            {
                using (FileStream savedSnapshot = new FileStream("Snapshots\\" + fileName + ".jpg", FileMode.CreateNew))
                {
                    if (File.Exists(fileName))
                    {
                        return;
                    }

                    BitmapSource image = (BitmapSource)ColorImageElement.Source;

                    JpegBitmapEncoder jpgEncoder = new JpegBitmapEncoder();

                    jpgEncoder.QualityLevel = 100;

                    jpgEncoder.Frames.Add(BitmapFrame.Create(image));

                    jpgEncoder.Save(savedSnapshot);

                    savedSnapshot.Flush();
                    savedSnapshot.Close();
                    savedSnapshot.Dispose();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Error in take snapshot" + e.Message);
            }
        }
    }




    public partial class App : Application
    {
        public static bool DEBUGon = true;

        protected override void OnStartup(StartupEventArgs e)
        {
            if (DEBUGon)
            {
                ConsoleHelper.AllocConsole();
                Console.SetBufferSize(100, (Int16.MaxValue - 1));
                Console.WriteLine("MainWindow");

            }
        }
    }
}

